using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Wax;

namespace Wax.Runner
{
    public partial class TestGrid : UserControl
    {
        #region Private fields

        /// <summary>
        /// Object that manages the loading and execution of tests
        /// </summary>
        private readonly TestRunner testRunner;

        /// <summary>
        /// Dictionary that allows finding of tree node for a given test.
        /// </summary>
        private Dictionary<Test, TreeNode> testNodeLookup;

        #endregion

        #region Constructors

        public TestGrid(TestRunner testRunner)
        {
            this.testRunner = testRunner;
            this.testRunner.LoadComplete += new EventHandler(TestRunnerLoadComplete);
            this.testRunner.TestStarted += new EventHandler(TestRunnerTestStarted);
            this.testRunner.TestCompleted += new EventHandler(TestRunnerTestCompleted);
            InitializeComponent();

            InitializeControls();
        }        

        #endregion

        #region Public events

        /// <summary>
        /// Occurs when a test item is selected.
        /// </summary>
        public event EventHandler ItemSelected;

        #endregion

        #region Private methods

        /// <summary>
        /// Initializes the controls.
        /// </summary>
        private void InitializeControls()
        {
            this.treeView.AfterSelect += new TreeViewEventHandler(TreeViewAfterSelect);
        }

        private void TreeViewAfterSelect(object sender, TreeViewEventArgs e)
        {
            if (this.ItemSelected != null)
            {
                this.ItemSelected(e.Node.Tag, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Handles the LoadComplete event of the testRunner control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TestRunnerLoadComplete(object sender, EventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new EventHandler(TestRunnerLoadComplete), new object[] { sender, e });
                return;
            }

            this.treeView.BeginUpdate();

            this.treeView.Nodes.Clear();
            this.testNodeLookup = new Dictionary<Test, TreeNode>();

            foreach (Test test in this.testRunner.Tests)
            {
                AddTestNode(test);
            }

            this.treeView.EndUpdate();
        }

        /// <summary>
        /// Adds a test node to the treeview control.
        /// </summary>
        /// <param name="test">The test.</param>
        private void AddTestNode(Test test)
        {
            TreeNode testNode = new TreeNode();
            testNode.Tag = test;
            this.testNodeLookup.Add(test, testNode);
            string labelEnd = test.Commands.Count == 1 ? "test" : "tests";
            testNode.Text = string.Format("{0} ({1} {2})", test.Id, test.Commands.Count, labelEnd);

            foreach (Command command in test.Commands)
            {
                AddCommandNode(testNode, command);
            }

            this.treeView.Nodes.Add(testNode);
        }

        /// <summary>
        /// Adds a command node to a given <paramref name="testNode"/>.
        /// </summary>
        /// <param name="testNode">The test node.</param>
        /// <param name="command">The command.</param>
        private void AddCommandNode(TreeNode testNode, Command command)
        {
            TreeNode commandNode = new TreeNode();
            commandNode.Text = command.Id;
            commandNode.Tag = command;

            testNode.Nodes.Add(commandNode);
        }

        /// <summary>
        /// Handles the <see cref="TestManager.TestCompleted"/> event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TestRunnerTestCompleted(object sender, EventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new EventHandler(TestRunnerTestCompleted), new object[] { sender, e });
                return;
            }

            Test test = sender as Test;

            if (test != null)
            {
                TreeNode node = this.testNodeLookup[test];
                node.Text = node.Text.Replace(" " + Resource.TestNodeExecutingSuffix, string.Empty);
            }
        }

        /// <summary>
        /// Handles the <see cref="TestManager.TestStarted"/> event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TestRunnerTestStarted(object sender, EventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new EventHandler(TestRunnerTestStarted), new object[] { sender, e });
                return;                          
            }

            Test test = sender as Test;

            if (test != null)
            {
                TreeNode node = this.testNodeLookup[test];
                node.Text = node.Text + " " + Resource.TestNodeExecutingSuffix;
            }
        }

        #endregion
    }
}
